

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>
#include "http_register.h"

#include "rapidjson/rapidjson.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "common_util.h"
#include "logging.h"
#include "json_rw_ID.h"

extern tbox_msg::jsonTboxId json_tbox_id;

const unsigned int IOT_ADD_RETRY_TIMES_MAX{6000};
const unsigned int IOT_ADD_RETRY_TIME_GAP{2}; // S

const std::string DEFALT_URL = "http://iot-test.imuyuan.com";
const std::string DEFALT_PATH = "/api/wlw/noToken/MyIot/add";

void toupper(std::string &str)
{
    int len = str.size();
    for (int i = 0; i < len; i++)
    {
        if (str[i] >= 'a' && str[i] <= 'z')
            str[i] -= 32;
    }
}

std::string CalcMD5(const std::string &src) // MD5算法加密 生成 sign
{
    // mbedtls_md5_context ctx;

    std::string md5_string;
    uint8_t md5_dest[16];
    std::ostringstream oss;
    const char *data;
    data = src.c_str();
    crypto_md5((uint8_t *)data, src.size(), md5_dest);
    for (int i = 0; i < 16; i++)
    {
        if (md5_dest[i] > 0xf)
            oss << std::hex << static_cast<int>(md5_dest[i]);
        else
        {
            oss << std::hex << static_cast<int>(0);
            oss << std::hex << static_cast<int>(md5_dest[i]);
        }
    }
    printf("\r\n");
    md5_string = oss.str();
    // md5_string = hexToStr(md5_dest,sizeof(md5_dest));
    toupper(md5_string);
    return md5_string;
}

std::string CalcSHA1(const std::string &src)
{
    std::string sha1_str;
    uint8_t sha1_dest[20];
    std::ostringstream oss;
    const char *data;
    data = src.c_str();
    crypto_sha1((uint8_t *)data, src.length(), sha1_dest);
    for (int i = 0; i < 20; i++)
    {
        if (sha1_dest[i] > 0xf)
            oss << std::hex << static_cast<int>(sha1_dest[i]);
        else
        {
            oss << std::hex << static_cast<int>(0);
            oss << std::hex << static_cast<int>(sha1_dest[i]);
        }
    }
    for (int i = 0; i < 20; i++)
    {
        printf("%02x", sha1_dest[i]);
    }
    sha1_str = oss.str();
    toupper(sha1_str);
    return sha1_str;
}

namespace httpRegisterDev
{
    httpRegister::httpRegister() : reister_curl(DEFALT_URL), curl_path(DEFALT_PATH)
    {
        reister_curl = DEFALT_URL;
        curl_path = DEFALT_PATH;
    }
    httpRegister::httpRegister(std::string url, std::string path) : reister_curl(url), curl_path(path)
    {
        reister_curl = url;
        curl_path = path;
    }
    void httpRegister::setRegisterInfo(std::string url, std::string url_path, std::string vcuId)
    {
        reister_curl = url;
        curl_path = url_path;
        deviceId = vcuId;                             //"MYRDB23060802222";
        device_version_id = "5yOJIdcK5mo0zuqadFNmEf"; // tbox 产品，不会改变从平台端要
        equiptype_id = "574i1yKTw3m0SduLBj1c5N";      // tbox 产品，不会改变从平台端要
        firmware_version = "1.0.1-default";
    }

    void httpRegister::setRegisterInfo(std::string vcuId)
    {
        reister_curl = "http://iot-test.imuyuan.com";
        curl_path = "/api/wlw/noToken/MyIot/add";
        deviceId = vcuId;                             //"MYRDB23060802222";
        device_version_id = "5yOJIdcK5mo0zuqadFNmEf"; // tbox 产品，不会改变从平台端要
        equiptype_id = "574i1yKTw3m0SduLBj1c5N";      // tbox 产品，不会改变从平台端要
        firmware_version = "1.0.1-default";
    }

    int httpRegister::register_device(std::string &user_name, std::string &password, std::string &client_id)
    {
        std::string sign;
        int return_code = 0;
        unsigned int retry_times_cnt = 0;
        std::string md5_content;
        rapidjson::StringBuffer buffer;
        rapidjson::Document document;
        std::string jsonToString;

        std::string device_secret;
        std::string device_name;
        std::string product_key;
        std::string product_version;

    iot_add_retry:
        timestamp = std::to_string(time(NULL)); // 1705549547

        md5_content = "deviceId" + deviceId + "device_version_id" + device_version_id + "equiptype_id" + equiptype_id + "firmware_version" + firmware_version + "time" + timestamp + "muyuan";
        sign = CalcMD5(md5_content);
        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
        writer.StartObject();
        writer.Key("deviceId");
        writer.String(rapidjson::StringRef(deviceId.c_str()));
        writer.Key("device_version_id");
        writer.String(rapidjson::StringRef(device_version_id.c_str()));
        writer.Key("equiptype_id");
        writer.String(rapidjson::StringRef(equiptype_id.c_str()));
        writer.Key("firmware_version");
        writer.String(rapidjson::StringRef(firmware_version.c_str()));
        writer.Key("time");
        writer.String(rapidjson::StringRef(timestamp.c_str()));
        writer.Key("sign");
        writer.String(rapidjson::StringRef(sign.c_str()));
        writer.EndObject();
        // document.Accept(writer);
        jsonToString = buffer.GetString();

        // 重复 3次
        try
        {
            httplib::Client cli(reister_curl);
            auto res2 = cli.Post(curl_path, jsonToString, "application/json");
            if (res2 && res2->status == 200)
            {
                LOG_INFO(" === Request successful: {} ===", jsonToString);
                rapidjson::Document document;
                document.Parse(res2->body.c_str());
                if (!(document.HasMember("data")))
                    printf("err here:%s,%d\r\n", __FILE__, __LINE__);
                else
                {
                    rapidjson::Value data;
                    data = document["data"]; // 使用一个新的rapidjson::Value来存放object
                    if (data.HasMember("rel"))
                    {
                        if (data["rel"].IsInt())
                            std::cout << "rel : " << data["rel"].GetInt() << std::endl;
                    }
                    if (data.HasMember("relCode"))
                    {
                        if (data["relCode"].IsInt())
                            std::cout << "relCode : " << data["relCode"].GetInt() << std::endl;
                    }
                    if (data.HasMember("deviceSecret"))
                    {
                        if (data["deviceSecret"].IsString())
                            device_secret = data["deviceSecret"].GetString();
                    }
                    if (data.HasMember("deviceName"))
                    {
                        if (data["deviceName"].IsString())
                            device_name = data["deviceName"].GetString();
                    }
                    if (data.HasMember("productKey"))
                    {
                        if (data["productKey"].IsString())
                            product_key = data["productKey"].GetString();
                    }
                    if (data.HasMember("version"))
                    {
                        if (data["version"].IsString())
                            product_version = data["version"].GetString();
                    }

                    std::string uuid = device_name; // 方便平台检测上下线消息
                    std::string client_id_ = uuid + "|securemode=3," + "signmethod=hmacsha1|";
                    // LOG_TRACE("====== client_id:%d", client_id);

                    std::string user_name_ = device_name + "&" + product_key;
                    std::string password_ = "clientId" + uuid + "deviceId" + device_name + "productKey" + product_key;
                    LOG_INFO(" === user_name:{}  ,password: {} === ", user_name, password);

                    std::string encrypt_passwd_ = CalcSHA1(password_);

                    json_tbox_id.user_name = user_name_;
                    json_tbox_id.password = encrypt_passwd_;
                    json_tbox_id.client_id = client_id_;
                    json_tbox_id.product_key = product_key;
                    json_tbox_id.device_name = device_name; // device_name
                    char *cwd = get_current_dir_name();
                    json_tbox_id.tbox_write_id(file_topdir,"my_test.json");
                    LOG_INFO(" === tbox_write_id: cwd {} === ", cwd);
                    free(cwd);

                    user_name = user_name_;
                    password = encrypt_passwd_;
                    client_id = client_id_;
                }
            }
        }
        catch (const std::exception &e)
        {
            LOG_ERROR("tbox client, reg add failed, catch msg:{},iov:{},cnt{}/max:{}",
                      e.what(), retry_times_cnt, IOT_ADD_RETRY_TIMES_MAX);
            return_code = -1;
            goto check_try_ornot;
        }

    check_try_ornot:
        if (0 != return_code)
        {
            if (retry_times_cnt <= IOT_ADD_RETRY_TIMES_MAX)
            {
                LOG_ERROR("tbox client, reg add failed, try again,,iov:{},cnt{}/max:{}",
                          reister_curl, retry_times_cnt, IOT_ADD_RETRY_TIMES_MAX);

                std::this_thread::sleep_for(std::chrono::seconds(IOT_ADD_RETRY_TIME_GAP));
                retry_times_cnt++;
                goto iot_add_retry;
            }
            else
            {
                LOG_ERROR("tbox client, reg add failed, out of max, exit,iov:{},cnt:{}/max:{}",
                          reister_curl, retry_times_cnt, IOT_ADD_RETRY_TIMES_MAX);
                return -1;
            }
        }

        return 0;
    }
}

// int test_rapidjson()
// {
//     // 1. 把 JSON 解析至 DOM。
//     const char *json = "{\"project\":\"rapidjson\",\"stars\":10}";
//     rapidjson::Document d;
//     d.Parse(json);

//     // 2. 利用 DOM 作出修改。
//     rapidjson::Value &s = d["stars"];
//     s.SetInt(s.GetInt() + 1);

//     // 3. 把 DOM 转换（stringify）成 JSON。
//     rapidjson::StringBuffer buffer;
//     rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
//     d.Accept(writer);

//     // Output {"project":"rapidjson","stars":11}
//     std::cout << buffer.GetString() << std::endl;
//     return 0;
// }
